import json
from dataclasses import dataclass, asdict
from typing import Optional
from random_str import generate_random_string


def to_json_(entity):

    def filter_none_values(d):
        if isinstance(d, dict):
            return {
                k: filter_none_values(v)
                for k, v in d.items() if v is not None
            }
        elif isinstance(d, list):
            return [filter_none_values(item) for item in d]
        else:
            return d

    if type(entity) == list and entity:
        # print(entity)
        for i in range(len(entity)):
            if type(entity[i]) == dict:
                continue
            node_dict = asdict(entity[i])
            filtered_dict = filter_none_values(node_dict)
            entity[i] = filtered_dict
        return json.dumps(entity, ensure_ascii=False)
    else:
        node_dict = asdict(entity)
        filtered_dict = filter_none_values(node_dict)
        return json.dumps(filtered_dict, ensure_ascii=False)


@dataclass
class JsonEntyty:

    def to_json(self):
        return to_json_(self)


@dataclass
class JsonList(JsonEntyty):

    def __init__(self, values=[]):
        self.values = values

    def to_json(self):
        return to_json_(self.values)

    def append(self, item):
        self.values.append(item)
    def clean(self):
        self.values = []


@dataclass
class Node(JsonEntyty):
    pass


@dataclass
class ContentNode(Node):
    fontSize: Optional[str]
    color: Optional[str]
    text: str

    def __init__(self,
                 font_size: Optional[str] = None,
                 color: Optional[str] = None,
                 text: str = '',
                 url: Optional[str] = None):
        self.text = str(text)
        self.fontSize = font_size
        self.color = color
        self.url = url


@dataclass
class StructNode(Node):
    id: str
    type: str
    children: list[Node]
    background: Optional[str]
    colSizes: Optional[list[int]]
    width: Optional[str]
    layout: Optional[str]

    def __init__(self,
                 type: str,
                 background: Optional[str] = None,
                 colSizes: Optional[list[int]] = None,
                 width: Optional[str] = None,
                 layout: Optional[str] = None):
        self.id = generate_random_string()
        self.type = type
        self.children = []
        self.background = background
        self.colSizes = colSizes
        self.width = width
        self.layout = layout

    def add_child(self, child: Node):
        self.children.append(child)


@dataclass
class TextNode(StructNode):

    def __init__(self,
                 type: str,
                 font_size: Optional[str] = None,
                 color: Optional[str] = None,
                 text: str = ''):
        super().__init__(type=type)
        self.add_child(ContentNode(font_size=font_size, color=color,
                                   text=text))


@dataclass
class UrlNode(StructNode):
    def __init__(self,
                 url: str,
                 font_size: Optional[str] = None,
                 color: Optional[str] = None,
                 text: str = ''):
        super().__init__(type="a")
        self.url = url
        self.add_child(ContentNode(font_size=font_size, color=color,
                                   text=text))


def get_td(text: str,
           font_size: str,
           color: str = None,
           background: str = None):
    td_node = StructNode(type="td", background=background)
    text_node = TextNode(type="p", font_size=font_size, color=color, text=text)
    td_node.add_child(text_node)
    return td_node


def get_tr(cols: list[str],
           font_size: str,
           color: str,
           background: str = None):
    row_node = StructNode(type="tr")
    for col in cols:
        row_node.add_child(
            get_td(text=col,
                   font_size=font_size,
                   color=color,
                   background=background))
    return row_node


def get_table(titles: list[str] = None,
              data: list[str] = None,
              titles_backound: str = None,
              titles_font_size: str = None,
              titles_color: str = None,
              data_color: str = None,
              data_font_size: str = None,
              data_background: str = None):
    cols = len(titles)
    rows = len(data)
    if rows == 0:
        data.append(['' for i in range(cols)])
        rows += 1
    table_node = StructNode(type="table")
    table_node.add_child(
        get_tr(titles,
               background=titles_backound,
               color=titles_color,
               font_size=titles_font_size))
    for i in range(rows):
        table_node.add_child(
            get_tr(data[i],
                   background=data_background,
                   color=data_color,
                   font_size=data_font_size))
    return table_node


def get_url_node(url: str):
    node = TextNode(type="p")
    un = UrlNode(url=url)
    node.add_child(un)
    return node
